package test.panel3;

import test.panel4.Control;
import test.panel4.Process;

import javax.swing.*;
import javax.swing.table.DefaultTableModel;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.*;

public class ProcessTableInPanel {
    public static ProcessTableInPanel instance = new ProcessTableInPanel();

    public static ProcessTableInPanel getInstance(){return instance;}

    public JPanel panel;
    private JTable table;
    private DefaultTableModel tableModel;
    private JTextField pidField, processNameField, memoryUsedField,
            memStartField, memEndField, diskStartField, diskEndField;

    private ProcessTableInPanel() {
        // 创建一个带有BorderLayout的面板。
        panel = new JPanel(new BorderLayout());

        // 创建并设置表格模型和表格。
        String[] columnNames = {"pid", "进程名", "占用内存", "内存中起始地址", "内存中终止地址", "磁盘中起始地址", "磁盘中终止地址", "占用磁盘大小"};
        tableModel = new DefaultTableModel(columnNames, 0);
        table = new JTable(tableModel);

        // 将表格添加到滚动面板中，并将其添加到面板上。
        JScrollPane scrollPane = new JScrollPane(table);
        panel.add(scrollPane, BorderLayout.CENTER);

    }

    private CustomPanel customPanel = CustomPanel.getInstance();
    private int memStartRows = 0, memStartCols = 0, memEndRows, memEndCols;
    private int disStartRows = 0, disStartCols = 0, disEndRows, disEndCols;
    private int disNum = 1024;
    private int memoryNum = 64;
    LinkedHashSet<Process> memSet = new LinkedHashSet<>();
    LinkedHashSet<Process> disSet = new LinkedHashSet<>();
    //ArrayList<Process> list = new ArrayList<>();

    // 添加数据
    public void addData(Process process){
        int pid = process.pid;
        String name = process.name;
        int memory = process.memory;

//        if (list.contains(process)){
//            list.remove(process);
//        }

        // 磁盘未满，添加到磁盘
        int maxDis = findMaxConnectedSpace(customPanel.diskBlocks,2); // 交换区
        int maxDis1 = findMaxConnectedSpace(customPanel.diskBlocks,1); // 文件区
        if (!disSet.contains(process)) {
            if (maxDis >= memory) {
                int[] maxSize = findMaxConnectedSpaceBySize(customPanel.diskBlocks, memory, 2);
                addDis(pid, name, memory, maxSize[1], maxSize[2]);
                disSet.add(process);
            }else if (maxDis1 >= memory) {
                int[] maxSize = findMaxConnectedSpaceBySize(customPanel.diskBlocks, memory, 1);
                addDis(pid, name, memory, maxSize[1], maxSize[2]);
                disSet.add(process);
            } else {
                JOptionPane.showMessageDialog(null, "磁盘空间不足。", "警告", JOptionPane.WARNING_MESSAGE);
            }
        }

        // 内存未满的情况
        int maxMem = findMaxConnectedSpace(customPanel.memoryBlocks,1);
        if (maxMem >= memory && !memSet.contains(process)) {
            int[] maxSize = findMaxConnectedSpaceBySize(customPanel.memoryBlocks, memory, 1);
            if (Objects.equals(process.getState(), "运行" )){
                addMemory(pid,name,memory,maxSize[1],maxSize[2]);
                memSet.add(process);
            }
        }

        // 内存已满
        if (maxMem < memory && !memSet.contains(process)) {
            while (maxMem < memory) { // 循环释放非运行状态的进程内存，直到满足条件
                boolean memoryFreed = false;
                Iterator<Process> iterator = memSet.iterator();

                // 遍历 memSet 释放非"运行"状态的进程内存
                while (iterator.hasNext()) {
                    Process process1 = iterator.next();
                    if (!process1.getState().equals("运行")) {
                        memoryNum += process1.memory;

                        // 获取当前进程所在的行索引
                        int index = getRowByPid(process1.pid);
                        Object[] rowData = getRowData(index);

                        // 清空表格中的相关数据
                        if (rowData != null && rowData.length > 4
                                && rowData[3] != null && rowData[4] != null) {
                            tableModel.setValueAt("", index, 2);
                            tableModel.setValueAt("", index, 3);
                            tableModel.setValueAt("", index, 4);

                            // 提取内存块数据，防止数组越界
                            String[] x1 = rowData[3].toString().split("[(),]");
                            String[] x2 = rowData[4].toString().split("[(),]");
                            if (x1.length > 2 && x2.length > 2) {
                                customPanel.setMemoryBlocks(
                                        Integer.parseInt(x1[1]),
                                        Integer.parseInt(x1[2]),
                                        Integer.parseInt(x2[1]),
                                        Integer.parseInt(x2[2]),
                                        Color.MAGENTA);
                            }
                        }

                        // 安全删除进程
                        iterator.remove();
                        memoryFreed = true;
                        break; // 释放一个进程后跳出当前循环
                    }
                }

                // 如果无法再释放任何进程内存，跳出外部循环
                if (!memoryFreed) {
                    break;
                }

                // 检查内存是否足够分配
                int max = findMaxConnectedSpace(customPanel.memoryBlocks, 1);
                if (max >= memory) {
                    int[] maxSize = findMaxConnectedSpaceBySize(customPanel.memoryBlocks, memory, 1);
                    if (maxSize != null && maxSize.length > 2) {
                        if (Objects.equals(process.getState(), "运行")) {
                            addMemory(process.pid, process.name, memory, maxSize[1], maxSize[2]);
                            memSet.add(process); // 将当前进程添加到 memSet
                        }
                    }
                    break; // 满足条件后退出外部循环
                }
            }
        }

    }

    // 删除数据
    public void deleteData(Process process){
        int pid = process.pid;
        String name = process.name;
        int memory = process.memory;

        int index = getRowByPid(pid);
        Object[] rowData = getRowData(index);
        // 删除内存数据
        if (memSet.contains(process)) {
            memoryNum += memory;
            String[] x1 = rowData[3].toString().split("[(),]");
            String[] x2 = rowData[4].toString().split("[(),]");
            customPanel.setMemoryBlocks(Integer.parseInt(x1[1]), Integer.parseInt(x1[2]), Integer.parseInt(x2[1]), Integer.parseInt(x2[2]), Color.MAGENTA);
            memSet.remove(process);
        }
        // 删除磁盘数据
        if (disSet.contains(process)) {
            disNum += memory;
            String[] x3 = rowData[5].toString().split("[(),]");
            String[] x4 = rowData[6].toString().split("[(),]");
            if (Integer.parseInt(x3[1]) >= 28){
                customPanel.setDiskBlocks(Integer.parseInt(x3[1]), Integer.parseInt(x3[2]), Integer.parseInt(x4[1]), Integer.parseInt(x4[2]), Color.GREEN);
            }else {
                customPanel.setDiskBlocks(Integer.parseInt(x3[1]), Integer.parseInt(x3[2]), Integer.parseInt(x4[1]), Integer.parseInt(x4[2]), Color.MAGENTA);
            }
            disSet.remove(process);
            tableModel.removeRow(index);
        }
    }

    // 修改进程占用磁盘大小
    public void updateDiskSize(int pid, int size){
        int index = getRowByPid(pid);
        Object[] rowData = getRowData(index);
        String[] x3 = rowData[5].toString().split("[(),]");
        String[] x4 = rowData[6].toString().split("[(),]");
        int maxDisk = findMaxConnectedSpace(customPanel.diskBlocks,2); // 交换区
        int maxDisk1 = findMaxConnectedSpace(customPanel.diskBlocks,1); // 文件区
        if (maxDisk >= size || maxDisk1 >= size) {
            if (Integer.parseInt(x3[1]) >= 28){
                customPanel.setDiskBlocks(Integer.parseInt(x3[1]), Integer.parseInt(x3[2]), Integer.parseInt(x4[1]), Integer.parseInt(x4[2]), Color.GREEN);
            }else {
                customPanel.setDiskBlocks(Integer.parseInt(x3[1]), Integer.parseInt(x3[2]), Integer.parseInt(x4[1]), Integer.parseInt(x4[2]), Color.MAGENTA);
            }
            if (maxDisk >= size){
                int[] maxSize = findMaxConnectedSpaceBySize(customPanel.diskBlocks, size, 2);
                disStartRows = maxSize[1];
                disStartCols = maxSize[2];
            }else {
                int[] maxSize = findMaxConnectedSpaceBySize(customPanel.diskBlocks, size, 1);
                disStartRows = maxSize[1];
                disStartCols = maxSize[2];
            }
            disEndRows = disStartRows + (disStartCols + size - 1)/32;
            disEndCols = (size + disStartCols - 1) % 32;
            customPanel.setDiskBlocks(disStartRows, disStartCols, disEndRows, disEndCols, Color.blue);
            tableModel.setValueAt("(" + disStartRows + "," + disStartCols + ")", index, 5);
            tableModel.setValueAt("(" + disEndRows + "," + disEndCols + ")", index, 6);
            tableModel.setValueAt(size, index, 7);
            disStartRows = disEndCols + 1 < 32 ? disEndRows : disEndRows + 1;
            disStartCols = disEndCols + 1 < 32 ? disEndCols + 1 : 0;
        }else {
            JOptionPane.showMessageDialog(null, "磁盘空间不足。", "警告", JOptionPane.WARNING_MESSAGE);
        }
    }

    // 添加数据到磁盘
    public void addDis (int pid, String name, int memory, int x, int y){
        disStartRows = x;
        disStartCols = y;
        disEndRows = disStartRows + (disStartCols + memory - 1)/32;
        disEndCols = (memory + disStartCols - 1) % 32;
        customPanel.setDiskBlocks(disStartRows, disStartCols, disEndRows, disEndCols, Color.blue);
        tableModel.addRow(new Object[]{pid, name, " ", " " , " ", "("+disStartRows+","+disStartCols+")", "("+disEndRows+","+disEndCols+")",memory});
        disStartRows = disEndCols + 1 < 32 ? disEndRows : disEndRows + 1;
        disStartCols = disEndCols + 1 < 32 ? disEndCols + 1 : 0;
        disNum -= memory;
    }

    // 添加数据到内存
    public void addMemory (int pid, String name, int memory, int x, int y){
        memStartRows = x;
        memStartCols = y;
        double memoryPer = memory / 64.0 * 100;
        memEndRows = memStartRows + (memStartCols + memory - 1)/8;
        memEndCols = (memory + memStartCols - 1) % 8;
        customPanel.setMemoryBlocks(memStartRows, memStartCols, memEndRows, memEndCols, Color.blue);
        int index = getRowByPid(pid);
        tableModel.setValueAt(memoryPer + "%", index, 2);
        tableModel.setValueAt("(" + memStartRows + "," + memStartCols + ")", index, 3);
        tableModel.setValueAt("(" + memEndRows + "," + memEndCols + ")", index, 4);
        memStartRows = memEndCols + 1 < 8 ? memEndRows : memEndRows + 1;
        memStartCols = memEndCols + 1 < 8 ? memEndCols + 1 : 0;
        memoryNum -= memory;
    }

    // 根据pid获取行号
    public int getRowByPid(int pid) {
        for (int i = 0; i < tableModel.getRowCount(); i++) {
            if ((Integer) tableModel.getValueAt(i, 0) == pid) { // 假设pid是第一列
                return i; // 返回行索引
            }
        }
        return -1; // 如果没有找到，返回-1
    }

    // 获取指定行的数据
    public Object[] getRowData(int rowIndex) {
        int columnCount = tableModel.getColumnCount(); // 获取列的数量
        Object[] rowData = new Object[columnCount]; // 创建一个数组来存储行数据

        for (int i = 0; i < columnCount; i++) {
            rowData[i] = tableModel.getValueAt(rowIndex, i); // 获取每一列的值
        }
        return rowData; // 返回整行数据
    }

    // 得到最大连续空间并返回大小
    public static int findMaxConnectedSpace(int[][] grid, int color) {
        int x = 0;
        int y = 0;
        if (grid == null || grid.length == 0 || grid[0].length == 0) {
            return 0;
        }

        int maxSpace = 0;
        int rows = grid.length;
        int cols = grid[0].length;

        boolean[][] visited = new boolean[rows][cols];

        // 遍历整个二维数组
        for (int i = 0; i < rows; i++) {
            for (int j = 0; j < cols; j++) {
                // 如果单元格是0且未访问过
                if (grid[i][j] == color && !visited[i][j]) {
                    // 检查水平连续空间大小
                    int horizontalSize = getHorizontalSize(grid, visited, i, j,color);
                    // 返回起始位置
                    /*if (maxSpace < horizontalSize){
                        x = i;
                        y = j;
                    }*/
                    maxSpace = Math.max(maxSpace, horizontalSize);
                }
            }
        }
        return maxSpace;
    }

    // 找到指定颜色和指定大小的连续空间
    public static int[] findMaxConnectedSpaceBySize(int[][] grid, int size, int color) {
        int x = 0;
        int y = 0;
        if (grid == null || grid.length == 0 || grid[0].length == 0) {
            return new int[]{};
        }

        int maxSpace = size;
        int rows = grid.length;
        int cols = grid[0].length;

        boolean[][] visited = new boolean[rows][cols];

        // 遍历整个二维数组
        for (int i = 0; i < rows; i++) {
            for (int j = 0; j < cols; j++) {
                // 如果单元格是0且未访问过
                if (grid[i][j] == color && !visited[i][j]) {
                    // 检查水平连续空间大小
                    int horizontalSize = getHorizontalSize(grid, visited, i, j,color);
                    // 返回起始位置
                    if (maxSpace <= horizontalSize){
                        x = i;
                        y = j;
                        return new int[]{maxSpace,x,y};
                    }
                    //maxSpace = Math.max(maxSpace, horizontalSize);
                }
            }
        }
        return new int[]{maxSpace,x,y};
    }

    // 计算连续空间大小
    private static int getHorizontalSize(int[][] grid, boolean[][] visited, int x, int y, int color) {
        int rows = grid.length;
        int cols = grid[0].length;
        int size = 0;

        // 遍历从当前单元格开始的水平线
        while (y < cols && grid[x][y] == color && !visited[x][y]) {
            visited[x][y] = true;
            size++;
            y++;
        }
        while (y == cols && (x < rows-1) && (grid[x][cols-1] == color) && grid[x+1][0] == color && !visited[x+1][0]){
            visited[x+1][0] = true;
            x++;
            y = 1;
            size++;
            while (y < cols && grid[x][y] == color && !visited[x][y]){
                visited[x][y] = true;
                size++;
                y++;
            }
        }
        return size;
    }
}
